﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.Data.SqlClient;
using System.Data;

using ESF.General;
using System.Collections.Specialized;
using System.Runtime.Serialization;

#endregion


namespace ESF.Data
{
	[Serializable]
	public class DbGenericException : GenericException
	{
		#region Constantes
		
		public const string DB_DATABASE_OUT_OF_REACH = "DB_DATABASE_OUT_OF_REACH";
		public const string DB_THEREIS_NO_DBCREDENTIAL = "DB_THEREIS_NO_DBCREDENTIAL";
		public const string DB_INVALID_DB_CREDENTIAL = "DB_INVALID_DB_CREDENTIAL";
		public const string DB_INSUFFICIENT_DB_RIGHTS = "DB_INSUFFICIENT_DB_RIGHTS";
		public const string DB_DUPLICITY_BY_CHECK = "DB_DUPLICITY_BY_CHECK";
		public const string DB_COMMAND_SINTAXIS_ERROR = "DB_COMMAND_SINTAXIS_ERROR";
		public const string DB_FK_REFERENCE_DEPENDS = "DB_FK_REFERENCE_DEPENDS";
		public const string DB_SYSTEM_DB_ERROR = "DB_SYSTEM_DB_ERROR";
		public const string DB_FIELD_DOESNOT_ACCEPT_NULL = "DB_FIELD_DOESNOT_ACCEPT_NULL";
		public const string DB_CUSTOM_ERROR = "DB_CUSTOM_ERROR";
		public const string DB_DUPLICITY_BY_INDEX = "DB_DUPLICITY_BY_INDEX";
		public const string DB_OTHER_REGISTER_WITH_SAME_IDENTITY_INFO = "DB_OTHER_REGISTER_WITH_SAME_IDENTITY_INFO";
		public const string DB_SYNTAXIS_ERROR = "DB_SYNTAXIS_ERROR";
		public const string DB_INVALID_COLUMN_MAPPING = "DB_INVALID_COLUMN_MAPPING";
		public const string DB_TIMEOUT = "DB_TIMEOUT";
		
		#endregion
	
	
		#region Constructor

		protected DbGenericException (SerializationInfo info, StreamingContext context) : base(info, context) { }


		public DbGenericException (string pProviderName, IDbCommand pCommand, Exception pInnerEx) :
			this (pProviderName, pCommand, pInnerEx, null) {}
			

		public DbGenericException (string pProviderName, IDbCommand pCommand, Exception pInnerEx, NameValueCollection pPartErrorMsg_ClientMsg) :
			this (pProviderName, pInnerEx.Message, pCommand, pInnerEx, pPartErrorMsg_ClientMsg) {}
			

		public DbGenericException (string pProviderName, string pMessage, IDbCommand pCommand, Exception pInnerEx) 
			: this (pProviderName, pMessage, pCommand, pInnerEx, null) {}  


		public DbGenericException (string pProviderName, string pMessage, IDbCommand pCommand, Exception pInnerEx, NameValueCollection pPartErrorMsg_ClientMsg) 
			: base (DB_SYSTEM_DB_ERROR, pMessage, pInnerEx, pPartErrorMsg_ClientMsg)
		{
			SqlException sqlEx;

			SqlError sqlErrorPrincipal;

			
			_DetailMessage = DbCommon.ToString (pProviderName, pCommand);
			
			#region SqlException
			
			if (pPartErrorMsg_ClientMsg == null)
			{
				if (pInnerEx is SqlException)
				{
					sqlEx = (SqlException) pInnerEx;

					sqlErrorPrincipal = sqlEx.Errors [0];

					_DetailMessage += Environment.NewLine + Environment.NewLine + sqlEx.Message + 
						Environment.NewLine + Environment.NewLine + "Line: " + sqlEx.Errors [0].LineNumber;

					switch (sqlErrorPrincipal.Number)
					{
						case 17:
							Code = DB_DATABASE_OUT_OF_REACH;
							_Message = "No hay acceso al servidor de base de datos, pruebe mas tarde";
							break;

						case 18452:
							Code = DB_THEREIS_NO_DBCREDENTIAL;
							_Message = "No hay credenciales de acceso al servidor de base de datos, intente mas tarde";
							break;
							
						case 18456:
							Code = DB_INVALID_DB_CREDENTIAL;
							_Message = "No hay credenciales de acceso validas al servidor de base de datos, intente mas tarde";
							break;
							
						case 4060:
							Code = DB_INSUFFICIENT_DB_RIGHTS;
							_Message = "No se cuenta con los permisos para acceder al servidor de base de datos, intente mas tarde";
							break;
							
						case 2627:
							Code = DB_OTHER_REGISTER_WITH_SAME_IDENTITY_INFO;
							_Message = "No se puede crear un nuevo registro.\nDebe modificar el registro existente";
							break;
							
						case 245:
							Code = DB_SYNTAXIS_ERROR;
							_Message = "Error de funcionamiento en el procedimiento";
							break;
							
						case 515:
							Code = DB_FIELD_DOESNOT_ACCEPT_NULL;
							_Message = "Se ha intentado insertar un valor nulo en un campo que no lo acepta";
							break;
							
						case 547:
						case 30001:
							Code = DB_FK_REFERENCE_DEPENDS;
							_Message = "Existe una referencia activa a este elemento, eliminelas para poder eliminar este elemento";
							break;
							
						case 50000:
							Code = DB_CUSTOM_ERROR;
							break;
							
						case 2601:
							Code = DB_DUPLICITY_BY_INDEX;
							_Message = "Registro duplicado por regla de indice unico";
							break;
							
						default:
							if (sqlErrorPrincipal.Message.ToLower ().Contains ("timeout"))
							{
								Code = DB_TIMEOUT;

                                _Message = "El servidor no atendio su solicitud dentro del tiempo limite esperado";

                                if (pCommand != null)
                                {
                                    _Message += string.Format(": {0}s", pCommand.CommandTimeout);
                                }
							} 
							else
							{
								_Message = string.Format (string.Format ("{0} [{1}]", Message, sqlErrorPrincipal.Number));
							}
							
							break;
					}
				}
			}
			
			#endregion
			
			// TODO: Soportar otros proveedores
		}
		
		#endregion
		
		
		#region Funciones

		public bool ConstraintExists (string pstrConstraintPart)
		{
			return (_DetailMessage.IndexOf (pstrConstraintPart) != -1);
		}
		
		
		public bool InvolucratedConstraintAndCode (string pstrCode, params string [] pstrConstraintParts)
		{
			bool blnContainsAll;
			
			
			blnContainsAll = true;
		
			foreach (string strConstraintPart in pstrConstraintParts)
			{
				blnContainsAll &= this.ConstraintExists (strConstraintPart);
			}

			return (blnContainsAll && Code == pstrCode);
		}
		
		#endregion
	}
}